【教程】从零开始搭建 k3s 集群

提示:本教程基于 Linux + fish shell 编写,个别命令语法与 Bash 略有差异。请结合自己的系统环境调整命令。
引言
众所周知,k3s 是由 Rancher Labs 开发的轻量级 Kubernetes 发行版,也是目前最流行的 K8s 轻量化方案。
相较于传统运维方式(1Panel/宝塔/SSH 等),k3s 的学习曲线更陡峭,需要理解更多容器编排概念。但一旦掌握,你将获得:
k3s 的核心优势
- 轻量高效 - 单个二进制文件,内存占用 < 512MB,完美适配低配 VPS
- 生产就绪 - 完全兼容 Kubernetes API,可平滑迁移到标准 K8s
- 声明式运维 - 用 YAML 描述期望状态,系统自动维护
- 高可用保障 - 自动故障恢复 + 多节点负载均衡
- 开箱即用 - 内置网络、存储、Ingress 等核心组件
通过 k3s,我们可以将多台廉价 VPS 整合为企业级高可用集群,实现传统运维难以达到的自动化水平。
目标读者与准备
适合人群
- 有一定 Linux 基础的开发者
- 希望从传统运维过渡到容器编排
- 想搭建个人高可用服务的技术爱好者
前置知识
- 熟悉 Linux 命令行操作
- 了解 Docker 容器基础
- 具备基本的网络知识(SSH、防火墙)
学习收获
完成本教程后,你将掌握:
- 使用 k3sup 快速部署 k3s 集群
- 理解 k3s 核心组件(API Server、etcd、kubelet 等)的作用
- 替换默认组件优化性能(Cilium CNI、Nginx Ingress 等)
- 部署第一个应用并配置外部访问
- 基本的集群运维和故障排查技巧
部署规划
k3s 默认安装了一套精简组件,为了满足生产级诉求,我们需要提前规划哪些模块要保留或替换。下表展示了推荐的取舍策略:
| 组件类型 | k3s 默认组件 | 替换组件 | 替换理由 | k3sup 禁用参数 |
|---|---|---|---|---|
| 容器运行时 | containerd | - | 保持默认即可 | - |
| 数据存储 | SQLite / etcd | - | 单节点用 SQLite,集群用 etcd | - |
| Ingress Controller | Traefik | Nginx Ingress / 其他 | 团队更熟悉、功能需求不同 | --disable traefik |
| LoadBalancer | Service LB (Klipper-lb) | 不想部署 | 懒得管负载均衡,直接买 cloudflare | --disable servicelb |
| DNS | CoreDNS | - | 保持默认即可 | - |
| Storage Class | Local-path-provisioner | Longhorn | 分布式存储、高可用、备份能力 | --disable local-storage |
| CNI | Flannel | Cilium | eBPF 性能、网络策略、可观测性 | --flannel-backend=none --disable-network-policy |

环境准备
必备工具
首先,确保 k3sup、kubectl、Helm 等工具已正确安装(可参考各自 GitHub 项目提供的安装说明):
k3sup version
kubectl version
helm version
如图所示:

服务器要求
准备至少三台云服务器(示例环境使用 Ubuntu 24.04),作为最小化三节点高可用控制平面(推荐配置 ≥ 4C4G)。提前记录各节点 IP、确认 SSH 公钥已分发,并知晓本地私钥路径,后续步骤会用到。
部署初始控制平面
使用 k3sup 部署初始控制节点:
k3sup install \
--ip 初始节点 IP \
--user root \
--ssh-key 密钥位置 \
--k3s-channel latest \
--cluster \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"
如图所示:

安装完成后,k3sup 会自动将 kubeconfig 复制到当前目录。虽然可以直接使用这份配置,但更加稳健的做法是与现有配置文件合并。
合并 kubeconfig
- 备份当前的 kubeconfig(默认位于
~/.kube/config):
cp ~/.kube/config ~/.kube/config.backup
fish shell(仅供参考):
cp $KUBECONFIG {$KUBECONFIG}.backup
- 将新旧 kubeconfig 合并为一份扁平文件:
KUBECONFIG=~/.kube/config:./kubeconfig kubectl config view --flatten > ~/.kube/config.new
fish shell(仅供参考):
KUBECONFIG=$KUBECONFIG:./kubeconfig kubectl config view --flatten > kubeconfig-merged.yaml
- 检查新文件内容无误后覆盖旧配置:
mv ~/.kube/config.new ~/.kube/config
fish shell:
mv ./kubeconfig-merged.yaml $KUBECONFIG
- 验证新上下文是否生效:
kubectl config get-contexts
kubectl config use-context default
安装 Cilium(替代 Flannel)
安装 k3s 时我们禁用了默认 CNI(Flannel),因此节点暂时无法互通。按计划部署 Cilium 以提供网络与网络策略能力。
使用 Helm 安装 Cilium:
# 添加 Cilium Helm 仓库
helm repo add cilium https://helm.cilium.io/
# 更新 Helm 仓库
helm repo update
# 安装 Cilium CNI(单副本,默认模式)
helm install cilium cilium/cilium \
--namespace kube-system \
--set operator.replicas=1 \
--set ipam.mode=kubernetes
如果集群已经禁用 kube-proxy,可额外添加
--set kubeProxyReplacement=strict。本教程保持默认值以兼容更多场景。
执行完成后可以看到:

等待 Cilium 组件启动完成:
# 查看 Cilium 相关 Pod 状态
kubectl get pods -n kube-system -l k8s-app=cilium
# 查看节点状态(应该从 NotReady 变为 Ready)
kubectl get nodes

节点切换到 Cilium 后应当从 NotReady 变为 Ready。接下来使用 k3sup 加入另外两个控制节点。
扩容控制平面
为了实现高可用,我们需要至少 3 个控制节点。使用以下命令加入第二个控制节点:
k3sup join \
--ip 第二个节点 IP \
--user root \
--ssh-key 密钥位置 \
--server-ip 初始节点 IP \
--server \
--k3s-channel latest \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"
同样的方式加入第三个控制节点:
k3sup join \
--ip 第三个节点 IP \
--user root \
--ssh-key 密钥位置 \
--server-ip 初始节点 IP \
--server \
--k3s-channel latest \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"
等待几分钟后检查集群状态:
kubectl get nodes
当三个控制节点均处于 Ready 状态时,控制平面即告搭建完成。

安装 Nginx Ingress Controller
替换 k3s 默认的 Traefik,安装 Nginx Ingress Controller:
# 添加 Nginx Ingress Helm 仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
# 安装 Nginx Ingress Controller(可能需要等待很久)
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.hostPort.enabled=true \
--set controller.hostPort.ports.http=80 \
--set controller.hostPort.ports.https=443 \
--set controller.service.type=ClusterIP
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

安装 Longhorn 分布式存储
Longhorn 是由 Rancher 开发的云原生分布式块存储系统,提供高可用、备份、快照等企业级功能。相比 k3s 默认的 local-path-provisioner,Longhorn 支持跨节点的持久化存储。
前置依赖检查
在安装 Longhorn 之前,需要确保每个节点都安装了必要依赖;若希望通过 Ansible 批量处理,可参考后续示例:
# 在每个节点上执行(通过 SSH)
# 检查并安装 open-iscsi
apt update
apt install -y open-iscsi nfs-common
# 启动并设置开机自启
systemctl enable --now iscsid
systemctl status iscsid
如果希望使用 Ansible 批量安装依赖,可以参考以下任务片段:
---
- name: Setup K3s nodes with Longhorn dependencies and CrowdSec
hosts: k3s
become: true
vars:
crowdsec_version: "latest"
tasks:
# ============================================
# Longhorn Prerequisites
# ============================================
- name: Install Longhorn required packages
ansible.builtin.apt:
name:
- open-iscsi # iSCSI support for volume mounting
- nfs-common # NFS support for backup target
- util-linux # Provides nsenter and other utilities
- curl # For downloading and API calls
- jq # JSON processing for Longhorn CLI
state: present
update_cache: true
tags: longhorn
- name: Enable and start iscsid service
ansible.builtin.systemd:
name: iscsid
enabled: true
state: started
tags: longhorn
- name: Load iscsi_tcp kernel module
community.general.modprobe:
name: iscsi_tcp
state: present
tags: longhorn
- name: Ensure iscsi_tcp loads on boot
ansible.builtin.lineinfile:
path: /etc/modules-load.d/iscsi.conf
line: iscsi_tcp
create: true
mode: '0644'
tags: longhorn
- name: Check if multipathd is installed
ansible.builtin.command: which multipathd
register: multipathd_check
failed_when: false
changed_when: false
tags: longhorn
- name: Disable multipathd if installed (conflicts with Longhorn)
ansible.builtin.systemd:
name: multipathd
enabled: false
state: stopped
when: multipathd_check.rc == 0
tags: longhorn
部署 Longhorn
使用 Helm 安装 Longhorn:
# 添加 Longhorn Helm 仓库
helm repo add longhorn https://charts.longhorn.io
helm repo update
# 安装 Longhorn(可能需要等待较长时间),请注意这里为了节约硬盘空间,只设置了单副本,请根据需求自行调整
helm install longhorn longhorn/longhorn \
--namespace longhorn-system \
--create-namespace \
--set defaultSettings.defaultDataPath="/var/lib/longhorn" \
--set persistence.defaultClass=true \
--set persistence.defaultClassReplicaCount=1
等待 Longhorn 组件启动:
# 查看 Longhorn 组件状态
kubectl get pods -n longhorn-system
# 查看 StorageClass
kubectl get storageclass

访问 Longhorn UI(可选)
Longhorn 提供了一个 Web UI 用于管理存储卷。可以通过端口转发临时访问:
# 端口转发到本地
kubectl port-forward -n longhorn-system svc/longhorn-frontend 8081:80
# 在浏览器访问 http://localhost:8081
完成查看后,请在终端按
Ctrl+C停止端口转发,避免持续占用本地端口。
加入 Agent 节点
目前为止,我们搭建了一个 3 节点的高可用控制平面(control-plane)。在生产环境中,我们不希望在 control-plane 节点上运行实际的应用程序(会占用 API Server、etcd 等核心组件的资源)。
因此,我们需要加入专门用于运行工作负载(Pods)的 Agent 节点(也称为 Worker 节点)。
安装前置依赖
与 control-plane 节点一样,Agent 节点也需要满足 Longhorn 的依赖(若希望这些节点能够调度并存储持久卷)。
在所有准备加入的 Agent 节点上,提前执行以下命令:
# 在每个 Agent 节点上执行(通过 SSH)
apt update
apt install -y open-iscsi nfs-common
# 启动并设置开机自启
systemctl enable --now iscsid
执行加入命令
添加 Agent 节点的命令与添加 control-plane 节点几乎一致,但有两个关键区别:不使用 --server 标记且无需额外参数。
k3sup join \
--ip <AGENT_节点 IP> \
--user root \
--ssh-key <密钥位置> \
--server-ip <任意 Control 节点 IP> \
--k3s-channel latest
验证节点状态
可以一次性加入多个 Agent 节点。添加完成后等待几分钟,Cilium 与 Longhorn 的组件会自动调度到新节点。
使用 kubectl 查看集群状态:
kubectl get nodes -o wide
你应该能看到新加入的节点,其 ROLE 列显示为 <none>(在 k3s 中,<none> 即代表 agent/worker 角色)。
同时,你可以监控 Cilium 和 Longhorn 的 Pod 是否在新节点上成功启动:
# Cilium agent 应该会在新节点上启动
kubectl get pods -n kube-system -o wide
# Longhorn instance-manager 应该也会在新节点上启动
kubectl get pods -n longhorn-system -o wide
至此,集群已经拥有了高可用的控制平面和用于运行应用的工作节点。
下一步行动
- 配置 Argo CD、Flux 等 GitOps 工具,将集群声明式管理流程标准化。
- 部署 Prometheus、Loki、Grafana 等可观测性组件,完善监控与日志体系。
- 使用 Ansible Playbook 自动化节点初始化与组件升级,降低后续运维成本。